using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Domain.Interfaces.Repositories;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    public class CommunityPostRepository : Repository<CommunityPost>, ICommunityPostRepository
    {
        public CommunityPostRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityPost>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(c => c.UserId == userId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPost>> GetByCategoryIdAsync(Guid categoryId)
        {
            return await _dbSet
                .Where(c => c.CategoryId == categoryId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPost>> GetByTagAsync(string tag)
        {
            return await _dbSet
                .Where(c => c.Tags.Contains(tag))
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPost>> GetByStatusAsync(string status)
        {
            return await _dbSet
                .Where(c => c.Status == status)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPost>> GetHotPostsAsync(int count)
        {
            return await _dbSet
                .Where(c => c.Status == "Published")
                .OrderByDescending(c => c.ViewCount)
                .ThenByDescending(c => c.LikeCount)
                .Take(count)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPost>> GetLatestPostsAsync(int count)
        {
            return await _dbSet
                .Where(c => c.Status == "Published")
                .OrderByDescending(c => c.CreatedTime)
                .Take(count)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPost>> SearchByContentAsync(string keyword)
        {
            return await _dbSet
                .Where(c => c.Title.Contains(keyword) || c.Content.Contains(keyword))
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }
    }

    public class CommunityPostCommentRepository : Repository<CommunityPostComment>, ICommunityPostCommentRepository
    {
        public CommunityPostCommentRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityPostComment>> GetByPostIdAsync(Guid postId)
        {
            return await _dbSet
                .Where(c => c.PostId == postId)
                .OrderBy(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPostComment>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(c => c.UserId == userId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPostComment>> GetByParentCommentIdAsync(Guid parentCommentId)
        {
            return await _dbSet
                .Where(c => c.ParentCommentId == parentCommentId)
                .OrderBy(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPostComment>> GetByPostIdOrderByCreatedTimeAsync(Guid postId)
        {
            return await _dbSet
                .Where(c => c.PostId == postId)
                .OrderBy(c => c.CreatedTime)
                .ToListAsync();
        }
    }

    public class CommunityPostLikeRepository : Repository<CommunityPostLike>, ICommunityPostLikeRepository
    {
        public CommunityPostLikeRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityPostLike>> GetByPostIdAsync(Guid postId)
        {
            return await _dbSet
                .Where(c => c.PostId == postId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPostLike>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(c => c.UserId == userId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<bool> IsUserLikedAsync(Guid userId, Guid postId)
        {
            return await _dbSet
                .AnyAsync(c => c.UserId == userId && c.PostId == postId);
        }

        public async Task<int> GetLikeCountByPostIdAsync(Guid postId)
        {
            return await _dbSet
                .CountAsync(c => c.PostId == postId);
        }
    }

    public class CommunityPostCollectionRepository : Repository<CommunityPostCollection>, ICommunityPostCollectionRepository
    {
        public CommunityPostCollectionRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityPostCollection>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(c => c.UserId == userId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityPostCollection>> GetByPostIdAsync(Guid postId)
        {
            return await _dbSet
                .Where(c => c.PostId == postId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<bool> IsUserCollectedAsync(Guid userId, Guid postId)
        {
            return await _dbSet
                .AnyAsync(c => c.UserId == userId && c.PostId == postId);
        }
    }

    public class CommunityCategoryRepository : Repository<CommunityCategory>, ICommunityCategoryRepository
    {
        public CommunityCategoryRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityCategory>> GetByParentIdAsync(Guid? parentId)
        {
            return await _dbSet
                .Where(c => c.ParentId == parentId)
                .OrderBy(c => c.Order)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityCategory>> GetActiveCategoriesAsync()
        {
            return await _dbSet
                .Where(c => c.IsActive)
                .OrderBy(c => c.Order)
                .ToListAsync();
        }

        public async Task<CommunityCategory> GetByCodeAsync(string code)
        {
            return await _dbSet
                .Where(c => c.Code == code)
                .FirstOrDefaultAsync();
        }
    }

    public class CommunityTagRepository : Repository<CommunityTag>, ICommunityTagRepository
    {
        public CommunityTagRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityTag>> GetByCategoryIdAsync(Guid categoryId)
        {
            return await _dbSet
                .Where(c => c.CategoryId == categoryId)
                .OrderBy(c => c.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityTag>> GetHotTagsAsync(int count)
        {
            return await _dbSet
                .OrderByDescending(c => c.UseCount)
                .Take(count)
                .ToListAsync();
        }

        public async Task<CommunityTag> GetByNameAsync(string name)
        {
            return await _dbSet
                .Where(c => c.Name == name)
                .FirstOrDefaultAsync();
        }
    }

    public class UserFriendRepository : Repository<UserFriend>, IUserFriendRepository
    {
        public UserFriendRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserFriend>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId)
                .OrderByDescending(u => u.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserFriend>> GetByFriendIdAsync(Guid friendId)
        {
            return await _dbSet
                .Where(u => u.FriendId == friendId)
                .OrderByDescending(u => u.CreatedTime)
                .ToListAsync();
        }

        public async Task<bool> IsUserFriendExistsAsync(Guid userId, Guid friendId)
        {
            return await _dbSet
                .AnyAsync(u => (u.UserId == userId && u.FriendId == friendId) || (u.UserId == friendId && u.FriendId == userId));
        }

        public async Task<UserFriend> GetByUserIdAndFriendIdAsync(Guid userId, Guid friendId)
        {
            return await _dbSet
                .Where(u => (u.UserId == userId && u.FriendId == friendId) || (u.UserId == friendId && u.FriendId == userId))
                .FirstOrDefaultAsync();
        }
    }

    public class UserFollowRepository : Repository<UserFollow>, IUserFollowRepository
    {
        public UserFollowRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserFollow>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId)
                .OrderByDescending(u => u.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserFollow>> GetByFollowedUserIdAsync(Guid followedUserId)
        {
            return await _dbSet
                .Where(u => u.FollowedUserId == followedUserId)
                .OrderByDescending(u => u.CreatedTime)
                .ToListAsync();
        }

        public async Task<bool> IsUserFollowedAsync(Guid userId, Guid followedUserId)
        {
            return await _dbSet
                .AnyAsync(u => u.UserId == userId && u.FollowedUserId == followedUserId);
        }

        public async Task<UserFollow> GetByUserIdAndFollowedUserIdAsync(Guid userId, Guid followedUserId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId && u.FollowedUserId == followedUserId)
                .FirstOrDefaultAsync();
        }
    }

    public class UserMessageRepository : Repository<UserMessage>, IUserMessageRepository
    {
        public UserMessageRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserMessage>> GetBySenderIdAsync(Guid senderId)
        {
            return await _dbSet
                .Where(u => u.SenderId == senderId)
                .OrderByDescending(u => u.SendTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserMessage>> GetByReceiverIdAsync(Guid receiverId)
        {
            return await _dbSet
                .Where(u => u.ReceiverId == receiverId)
                .OrderByDescending(u => u.SendTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserMessage>> GetConversationAsync(Guid userId1, Guid userId2)
        {
            return await _dbSet
                .Where(u => (u.SenderId == userId1 && u.ReceiverId == userId2) || (u.SenderId == userId2 && u.ReceiverId == userId1))
                .OrderBy(u => u.SendTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserMessage>> GetUnreadMessagesByReceiverIdAsync(Guid receiverId)
        {
            return await _dbSet
                .Where(u => u.ReceiverId == receiverId && !u.IsRead)
                .OrderBy(u => u.SendTime)
                .ToListAsync();
        }

        public async Task<int> GetUnreadCountByReceiverIdAsync(Guid receiverId)
        {
            return await _dbSet
                .CountAsync(u => u.ReceiverId == receiverId && !u.IsRead);
        }
    }

    public class CommunityGroupRepository : Repository<CommunityGroup>, ICommunityGroupRepository
    {
        public CommunityGroupRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityGroup>> GetByCategoryIdAsync(Guid categoryId)
        {
            return await _dbSet
                .Where(c => c.CategoryId == categoryId)
                .OrderBy(c => c.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityGroup>> GetByCreatorIdAsync(Guid creatorId)
        {
            return await _dbSet
                .Where(c => c.CreatorId == creatorId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityGroup>> GetByStatusAsync(string status)
        {
            return await _dbSet
                .Where(c => c.Status == status)
                .OrderBy(c => c.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityGroup>> SearchByNameAsync(string keyword)
        {
            return await _dbSet
                .Where(c => c.Name.Contains(keyword))
                .OrderBy(c => c.Name)
                .ToListAsync();
        }
    }

    public class CommunityGroupMemberRepository : Repository<CommunityGroupMember>, ICommunityGroupMemberRepository
    {
        public CommunityGroupMemberRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityGroupMember>> GetByGroupIdAsync(Guid groupId)
        {
            return await _dbSet
                .Where(c => c.GroupId == groupId)
                .OrderBy(c => c.JoinTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityGroupMember>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(c => c.UserId == userId)
                .OrderByDescending(c => c.JoinTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityGroupMember>> GetByGroupIdAndRoleAsync(Guid groupId, string role)
        {
            return await _dbSet
                .Where(c => c.GroupId == groupId && c.Role == role)
                .OrderBy(c => c.JoinTime)
                .ToListAsync();
        }

        public async Task<bool> IsUserMemberOfGroupAsync(Guid userId, Guid groupId)
        {
            return await _dbSet
                .AnyAsync(c => c.UserId == userId && c.GroupId == groupId);
        }

        public async Task<CommunityGroupMember> GetByUserIdAndGroupIdAsync(Guid userId, Guid groupId)
        {
            return await _dbSet
                .Where(c => c.UserId == userId && c.GroupId == groupId)
                .FirstOrDefaultAsync();
        }
    }

    public class CommunityGroupPostRepository : Repository<CommunityGroupPost>, ICommunityGroupPostRepository
    {
        public CommunityGroupPostRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<CommunityGroupPost>> GetByGroupIdAsync(Guid groupId)
        {
            return await _dbSet
                .Where(c => c.GroupId == groupId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityGroupPost>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(c => c.UserId == userId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<CommunityGroupPost>> GetByGroupIdOrderByCreatedTimeAsync(Guid groupId)
        {
            return await _dbSet
                .Where(c => c.GroupId == groupId)
                .OrderByDescending(c => c.CreatedTime)
                .ToListAsync();
        }
    }
}